Repository navigation
refactor: remove unused cast compatibility flag - #6135
Conversation
andygrove
left a comment
There was a problem hiding this comment.
Thanks for picking this up. The cleanup reads nicely, and the reserved lines match how we retire proto fields elsewhere. native/core doesn't compile with this change though. schema_adapter.rs:1353 still passes self.parquet_options.allow_incompat as a third argument to SparkCastOptions::new, and cargo check --workspace --all-targets fails with error[E0061]: this function takes 2 arguments but 3 arguments were supplied. Could you drop that argument? Running cargo clippy --all-targets --workspace -- -D warnings from native/ is what CI runs, so it will catch anything else across the crates.
Once that argument is gone, SparkParquetOptions::allow_incompat in parquet_support.rs has no reader left. The production constructors in parquet_exec.rs and iceberg_scan.rs both pass false, and the field still has the "Allow casts that are supported but not guaranteed to be 100% compatible" doc comment. That leaves readers with the same wrong impression #5077 is trying to remove. Would you be up for removing it from SparkParquetOptions and its two constructors in this PR too? Most of the call sites are tests.
The flag has no remaining reader after the cast-option cleanup, and the unused CometConf import fails scalafix.
sunchao
left a comment
There was a problem hiding this comment.
Summary
- Prior state and problem:
allowIncompatiblewas enforced during JVM planning but also serialized and carried through unused native options. - Design approach: Remove that dead state from cast and Parquet options without introducing another abstraction.
- Correctness / compatibility analysis: The production cast and Parquet conversion kernels are unchanged. JVM compatibility gating, eval modes, timezones, and Spark-version handling remain intact. Checked relevant Spark sources for 3.4.3, 3.5.9, 4.0.4, 4.1.3, and 4.2.0.
- Key design decisions: Reserving protobuf field
5andallow_incompatpreserves the remaining wire contract. The change adds no execution work or allocations. - Implementation sketch: Update serializers, constructors, planner and scan callers, tests, benchmarks, and audit documentation. Remove unused
CometEvalModehelpers. The previously reported constructor-arity and unused-import concerns are fixed. - Behavioral changes worth calling out: No cast-result or fallback-policy changes identified. No introduced P1/P2 issues found within this review.
- Suggested improvements: None at P1/P2 priority.
Reviewed all 35 changed files at bd3ac92f8ad1d12248bac645e1aee81566cc7559 against 7ee863ed5096049844cd05c635bc254cbaded804, including both cleanup commits. Confirmed non-draft status and read all supplied discussion. Routed skills: review-comet-pr and review-comet-expression-pr.
Exact-head CI: Only the labeling job passed. Comet CI and CodeQL report action_required, providing no build or test verdict.
Validation: cargo check --locked --offline --workspace --all-targets passed. Protobuf checks passed 36 old-to-new and 18 new-to-old cases. The focused native conversion-test attempt reached its 180-second limit while compiling dependencies, before tests ran. JVM, Spark SQL, and Iceberg suites were not run. Runtime validation therefore remains outstanding.
|
This is a light fully automated review since there are so many PRs open. The |
…ansi-cast # Conflicts: # spark/src/main/scala/org/apache/comet/rules/RevertNativeForTransitionHeavyStages.scala
andygrove
left a comment
There was a problem hiding this comment.
Thanks for the updates. The constructor arity errors, the unused import and the leftover SparkParquetOptions::allow_incompat are all addressed, and I no longer see a three-argument call in any test module. I have one question about scope on the new commit cefe845a1.
| case cometExec: CometExec => | ||
| if (cometExec.originalPlan.children.size == cometExec.children.size) { | ||
| cometExec.originalPlan.withNewChildren(cometExec.children) | ||
| val originalWithCurrentExpressions = cometExec match { |
There was a problem hiding this comment.
This change and its two tests are not part of the allowIncompatible cleanup. The CometNativeScanExec branch and the RevertNativeForTransitionHeavyStagesSuite test are the same fix as #6137 (which closes #5486), so whichever PR lands second will conflict on this hunk. The CometIcebergNativeScanExec branch is also only in this PR, so it will not be reviewed or merged with the V1 fix. The description here still says the PR does not change behavior and adds no tests. Could we drop cefe845a1 from this PR and move the Iceberg case into #6137? That keeps this PR a pure no-behavior-change cleanup and lets the DPP fix be reviewed with its own description.
…si-cast Co-authored-by: Cursor <cursoragent@cursor.com>
…si-cast Co-authored-by: Cursor <cursoragent@cursor.com>
…ansi-cast # Conflicts: # native/spark-expr/src/conversion_funcs/string.rs
|
@sam-1112 let me know when this is ready for another review |
|
@andygrove It's ready for another review. Sorry for the late heads-up! |
apache#6648 added this bench after the last merge of main into this branch, and it still passed the third argument that this PR removes from SparkCastOptions::new.
andygrove
left a comment
There was a problem hiding this comment.
Thanks for the updates. The earlier items are all addressed, including the DPP change coming out of this PR.
One more break came in from main that you couldn't have seen. #6648 added native/spark-expr/benches/cast_nested.rs on 10-06, after your last merge, and it still passes the removed third argument to SparkCastOptions::new. Merged with this PR, cargo clippy --all-targets, which CI runs, fails with E0061 on that line. I merged the latest main into this branch and dropped the argument in a separate commit (66e7c77) so the fix is easy to see. Nothing else changed.
I ran the Rust unit tests, the Spark 3.5 scalafix check, and the cast, temporal and Parquet read suites on a local merge with main. On the pushed head I then ran clippy with -D warnings, cargo check --benches and cargo fmt --check. All of them pass. I also checked branch-1.1 and main for a native read of allow_incompat and found none, so the flag was dead on the native side and this is a pure removal.
apache#6135 removed the allow_incompat argument of SparkCastOptions::new and new_without_timezone. The conflict in case_when.rs's test, and the two casts in null_short_circuit.rs's tests, now drop it too.
apache#6135 removed the third argument of SparkCastOptions::new on main.
…apache#6841) * fix: accept all BMP Unicode decimal digits in cast(string as decimal) Spark casts a string to decimal with `new java.math.BigDecimal(s.trim)`, which accepts any char for which `Character.isDigit(char)` is true, in both the mantissa and the exponent. Comet only normalized fullwidth digits, so strings such as '٣' (U+0663 ARABIC-INDIC DIGIT THREE) or '1e३' returned NULL, or raised CAST_INVALID_INPUT under ANSI, where Spark returns a value. Normalize every non-ASCII Nd digit in the Basic Multilingual Plane to ASCII before parsing. Supplementary-plane digits stay rejected, since BigDecimal sees them as surrogate pairs. The pure-ASCII fast path is unchanged. Integral, floating-point and date casts are left alone: Spark only accepts ASCII digits there. * perf: keep ASCII and fullwidth digits off the table lookup Normalizing every char through the Nd table slowed down already supported fullwidth and mixed ASCII/fullwidth input. Scan bytes instead, copying ASCII directly and mapping the fullwidth UTF-8 encoding in place as before, and only decode a char for the table lookup otherwise. The output buffer is preallocated, since it is never longer than the input. Add fullwidth, mixed ASCII/fullwidth and Arabic-Indic cases to the cast_from_string benchmark. * fix: drop removed SparkCastOptions argument in the new decimal benchmark apache#6135 removed the third argument of SparkCastOptions::new on main.
Which issue does this PR close?
Closes #5077.
Rationale for this change
allowIncompatiblecontrols whether the JVM planner may offload casts that are not guaranteed to be fully compatible. It is a JVM planning decision, but it was unnecessarily serialized in theCastprotobuf and carried through native cast options despite having no native consumer.Keeping this unused flag in the JVM-to-native contract obscures the ownership of the compatibility decision and leaves dead state in the native cast API.
What changes are included in this PR?
allow_incompatinCastexpressions.SparkCastOptions.allowIncompatibleis enforced by the JVM planner only.How are these changes tested?
No new tests were added because this PR removes unused JVM-to-native cast-option plumbing and does not change cast behavior.